//
// Created on 2024/5/15.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include "export.h"
#include "Export/export_gfx.h"
#include "mlog.h"
#include "napi.h"
#include "thread/thread.h"
#include <bits/alltypes.h>
#include <map>
#include <rawfile/raw_file_manager.h>

// 记录注册的事件

static std::map<DispatchEventType, CallBackInfo> map_funcref;
static std::map<DispatchEventType, CallBackData> map_funcdata;
static std::map<std::string, napi_threadsafe_function> map_threadsafe_handle;
static std::map<uint64_t, uint64_t> map_threadcallcounter;


// 初始化NAPI,提供Resmgr，这样我们才可以加载资源
static napi_value Game_Init(napi_env env, napi_callback_info info) {
    MLOG("Game_Init.napi_Init...");
    size_t argc;
    napi_value argv[1] = {nullptr};
    // 获取参数信息
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[0]);

    RawDir *dir = OH_ResourceManager_OpenRawDir(mNativeResMgr, "");
    MLOGFormat("dir = %{public}ld", dir);
    if (dir != nullptr) {
        int filecount = OH_ResourceManager_GetRawFileCount(dir);
        for (int i = 0; i < filecount; i++) {
            std::string name = OH_ResourceManager_GetRawFileName(dir, i);
            MLOGFormat("dirfile = %{public}ld %{public}s", i, name.c_str());
        }
        OH_ResourceManager_CloseRawDir(dir);
    }

    return nullptr;
}

// 异步派发事件用的
static void hm_threadsafe_func(napi_env env, napi_value js_fun, void *context, void *data) {
    {

        size_t argc = 0;
        napi_value out_value = NULL;
        napi_status ret = napi_call_function(env, NULL, js_fun, argc, (const napi_value *)nullptr, &out_value);
        if (context != nullptr) {
            // 检查有没有需要释放的函数句柄
            std::string key = (char *)context;
            auto it = map_threadsafe_handle.find(key);
            if (it != map_threadsafe_handle.end()) {
                if (it->second != nullptr)

                {
                    napi_release_threadsafe_function(it->second, napi_tsfn_release);
                }
            }
        }
    }
}

// 派发事件
bool DispatchEvent(DispatchEventType type, DispatchMode mode) {
    auto it = map_funcref.find(type);
    if (it == map_funcref.end())
        return false;
    napi_value func;
    auto env = it->second.env;
    napi_get_reference_value(env, it->second.ref_func, &func);
    if (func == nullptr)
        return false;
    if (mode == Direct) {

        napi_value result;
        napi_call_function(env, (napi_value) nullptr, (napi_value)func, (size_t)0, (const napi_value *)nullptr,
                           &result);
        return true;
    } else if (mode == Thread_Block) {
        napi_threadsafe_function tfunc;
        napi_status status =
            napi_create_threadsafe_function(env, (napi_value)func, (napi_value)NULL, (napi_value) "threadsafe_func", 0,
                                            1, NULL, NULL, NULL, &hm_threadsafe_func, &tfunc);
        napi_call_threadsafe_function(tfunc, nullptr, napi_tsfn_blocking);
        napi_release_threadsafe_function(tfunc, napi_tsfn_release);
        return true;
    } else if (mode == Thread_NoBlock) {
        auto tid = getThreadID();
        uint64_t counter = 0;
        auto itcounter = map_threadcallcounter.find(tid);
        if (itcounter == map_threadcallcounter.end())
            counter = 0;
        else {
            counter = itcounter->second;
        }
        counter++;
        map_threadcallcounter[tid] = counter;

        std::string key = "_";
        key += tid;
        key += "_";
        key += counter;


        napi_threadsafe_function tfunc;
        napi_status status =
            napi_create_threadsafe_function(env, (napi_value)func, (napi_value)NULL, (napi_value) "threadsafe_func", 0,
                                            1, NULL, NULL, (void *)key.c_str(), &hm_threadsafe_func, &tfunc);
        napi_call_threadsafe_function(tfunc, nullptr, napi_tsfn_blocking);
        napi_release_threadsafe_function(tfunc, napi_tsfn_release);
        map_threadsafe_handle[key] = tfunc;

        return true;
        ;
    } else {
        throw "fuck.";
        return false;
    }
}

// 设置回调方法
static napi_value Game_SetCallBack(napi_env env, napi_callback_info info) {

    MLOG("Game_SetCallBack...");
    size_t argc = 2;
    napi_value argv[2];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    DispatchEventType type;
    napi_get_value_uint32(env, argv[0], (uint32_t *)&type);
    napi_ref ref;
    auto func = argv[1];
    napi_create_reference(env, func, 1, &ref);

    CallBackInfo saveinfo;
    saveinfo.env = env;
    saveinfo.ref_func = ref;
    // saveinfo.reg_data=new uint32_t[8];


    // saveinfo.reg_value =nullptr;
    // napi_value reg_value = nullptr;
    // napi_create_arraybuffer(env, 32, (void **)&saveinfo.reg_data, &saveinfo.reg_value);
    // napi_create_reference(env, reg_value, 1, &saveinfo.reg_ref);
    // 创建一个寄存器区域用作回调数据交换
    map_funcref[type] = saveinfo;
    
    GetCallBackData(type);//顺便把Data也初始化出来

    return nullptr;
}
CallBackData GetCallBackData(DispatchEventType type) {
    auto it = map_funcdata.find(type);
    if (it == map_funcdata.end()) {
        CallBackData data;
        data.reg_data = new uint32_t[4];
        data.reg_data_len = 32;
        map_funcdata[type] = data;
        return data;
    }

    return it->second;
}
//这个方法可能从多个线程初始化，需要加个锁
napi_value Game_GetCallBackReg(napi_env env, napi_callback_info info) {
    size_t argc = 1;
    napi_value argv[1];
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);

    DispatchEventType type;
    napi_get_value_uint32(env, argv[0], (uint32_t *)&type);
    CallBackData data =GetCallBackData((type));
   

    napi_value reg_value = nullptr;

    // 这个变量是个一次性的,存起来不行
    // if(it->second.reg_value==nullptr)
    // 复用同一块内存
    {
        napi_create_external_arraybuffer(
            env, (void *)data.reg_data, data.reg_data_len, [](napi_env env, void *data, void *hint) {},
            nullptr, // 这个finallize 不能为空
            &reg_value);
    }

    return reg_value;
}

// 创建一个寄存器，避免反复传参
static napi_value reg_entity = nullptr;
static uint32_t *data_entity;
static napi_value Game_GetReg_Entity(napi_env env, napi_callback_info info) {
    MLOG("Game_GetReg_Entity...");

    if (reg_entity == nullptr) {
        napi_create_arraybuffer(env, 8, (void **)&data_entity, &reg_entity);
    }
    return reg_entity;
}

static napi_value Game_CreateEntity(napi_env env, napi_callback_info info) {
    MLOG("Game_CreateEntity...");

    uint32_t ver = 3;
    uint32_t index = 788;


    // 把值装进指定的数组
    data_entity[0] = index;
    data_entity[1] = ver;


    return nullptr;
}
static napi_value Game_GetCurThreadID(napi_env env, napi_callback_info info) {
    auto t = getThreadID();

    napi_value returnv;
    napi_create_double(env, (double)(int64_t)t, &returnv);
    return returnv;
}

//////////////////////////////////////////////////////////////////////////////////////////////
//新老分界线



void ExportNAPIFunction(napi_env env, napi_value exports) {

    napi_property_descriptor desc[] = {
        //{"add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr}
        {"Game_Init", nullptr, &Game_Init, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"Game_GetCurThreadID", nullptr, &Game_GetCurThreadID, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"Game_SetCallBack", nullptr, &Game_SetCallBack, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"Game_GetCallBackReg", nullptr, &Game_GetCallBackReg, nullptr, nullptr, nullptr, napi_default, nullptr},

        {"Game_GetReg_Entity", nullptr, &Game_GetReg_Entity, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"Game_CreateEntity", nullptr, &Game_CreateEntity, nullptr, nullptr, nullptr, napi_default, nullptr},
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);

    ExportNAPIFunction_GFX(env,exports);
}
